package com.example.byexample       // 1

fun main() {                        // 2
    println("Hello, World!")        // 3

    // 函数
    printMessage("Hello!")

    // 默认参数值和命名参数
    printMessageWithPrefix("Hello!")
    printMessageWithPrefix("Hello!", prefix = "Log")
    printMessageWithPrefix(message = "Hello!", prefix = "Log")

    println(sum(1, 2))
    // 单表达式函数
    println(multiply(2, 4))

    // 中缀函数
    infix fun Int.times(str: String) = str.repeat(this)
    println(2 times "Bye ")

    val pair = "Ferrari" to "Katrina"
    println(pair)

    infix fun String.onto(other: String) = Pair(this, "pair")

    val myPair = "McLaren" onto "Lucas"
    println(myPair)

    val sophia = Person("Sophia")
    val claudia = Person("Claudia")
    sophia likes claudia

    // 运算符函数
    operator fun Int.times(str: String) = str.repeat(this) // 乘法
    println(2 * "Bye ")

    operator fun String.get(range: IntRange) = substring(range) // 字符串索引取值
    val str = "Always forgive your enemies; nothing annoys them so much."
    println(str[0..14])

    // 可变参数的函数
    printAll("Hello", "Hallo", "Salut", "Hala", "你好")
    printAllWithPrefix(
        "Hello", "Hallo", "Salut", "Hola", "你好", prefix = "Greeting: "
    )
    log("Hello", "Hallo", "Salut", "Hala", "你好")

    // 变量
    var a: String = "initial"
    println(a)
    val b: Int = 1
    val c = 3

    var e: Int
    println(e) // Variable 'e' must be initialized

    val d: Int
    if (1 == 2) {
        d = 1
    } else {
        d = 2
    }
    println(d)

    // 空安全，默认非空
    var neverNull: String = "This can't be null"
//     neverNull = null
    var nullable: String? = "You can keep a null here"
    nullable = null
    var inferredNonNull = "The compiler assumes non-null"

    // inferredNonNull = null
    fun strLength(notNull: String): Int {
        return notNull.length
    }
    strLength(neverNull)
    // strLength(nullable)

    // 使用空值
    fun describeString(maybeString: String?): String {
        if (maybeString != null && maybeString.length > 0) {
            return "String of length ${maybeString.length}"
        } else {
            return "Empty or null string"
        }
    }

    // 类
    val customer = Customer()
    val contact = Contact(1, "name@example.com")
    println(contact.id)
    contact.email = "hane@gmail.com"

    // 泛型
    val doubleStack = mutableStackOf(0.62, 3.14, 2.7)
    println(doubleStack)

    val intStack = mutableStackOf(62, 14, 27)
    println(intStack)

    // 继承
    val dog: Dog = Yorkshire()
    dog.sayHello()
    val lion: Lion = Asiatic("Rufo")
    lion.sayHello()
}

// In Kotlin versions earlier than 1.3, the main function must have a parameter of type Array<String>.
//fun main(args: Array<String>) {
//    println("Hello, World!")
//}

class MyClass

open class Lion(val name: String, val origin: String) {
    fun sayHello() {
        println("$name, the lion from $origin say: graoh!")
    }
}

class Asiatic(name: String) : Lion(name = name, origin = "India")

open class Dog { // Kotlin 类默认是 final 的。如果要允许类继承，请使用 open 修饰符标记该类。
    open fun sayHello() { // 默认情况下，Kotlin 方法也是 final 的。与类一样， open 修饰符允许覆盖它们。
        println("wow wow!")
    }
}

class Yorkshire : Dog() { // 当您在其名称后指定 : SuperclassName() 时，类将继承超类。空括号 () 表示调用超类默认构造函数。
    override fun sayHello() { // Overriding methods or attributes requires the override modifier.
        println("wif wif!")
    }
}

fun <E> mutableStackOf(vararg element: E) = MutableStack(*element)

class MutableStack<E>(vararg items: E) {
    private val elements = items.toMutableList();

    fun push(element: E) = elements.add(element)

    fun peek(): E = elements.last()

    fun pop(): E = elements.removeAt(elements.size - 1)

    fun isEmpty() = elements.isEmpty()

    fun size() = elements.size

    override fun toString() = "MutableStack(${elements.joinToString()})"
}

class Customer

class Contact(val id: Int, var email: String)

fun log(vararg entries: String) {
    printAll(*entries)
}

fun printAllWithPrefix(vararg messages: String, prefix: String) {
    for (m in messages) println(prefix + m)
}

fun printAll(vararg messages: String) {
    for (msg in messages) {
        println(msg)
    }
}

class Person(val name: String) {
    private val likedPeople = mutableListOf<Person>()
    infix fun likes(other: Person) {
        likedPeople.add(other)
    }
}

fun printMessage(message: String) {
    println(message)
}

fun printMessageWithPrefix(message: String, prefix: String = "Info") {
    println("[$prefix] $message")
}

//fun sum(x: Int, y: Int): Int {
//    return x + y
//}

fun multiply(x: Int, y: Int) = x * y
